package com.ihm.projetihm_v1.nf;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

/**
 * 
 * @author Adrien
 *
 */
public class LinkedPhoto
{
	//+++++++++++//
	// CONSTANTS //
	//+++++++++++//

	public static enum RELATION_TYPE
	{
		NORTH
		{
			@Override
			public String getName(){ return "north"; }
		},
		NORTH_EAST
		{
			@Override
			public String getName(){ return "northEast"; }
		},
		EAST
		{
			@Override
			public String getName(){ return "east"; }
		},
		SOUTH_EAST
		{
			@Override
			public String getName(){ return "southEast"; }
		},
		SOUTH
		{
			@Override
			public String getName(){ return "south"; }
		},
		SOUTH_WEST
		{
			@Override
			public String getName(){ return "southWest"; }
		},
		WEST
		{
			@Override
			public String getName(){ return "west"; }
		},
		NORTH_WEST
		{
			@Override
			public String getName(){ return "northWest"; }
		};
		public abstract String getName();
		public static RELATION_TYPE getTypeFromName(String typeName)
		{
			for (RELATION_TYPE type : RELATION_TYPE.values())
			{
				if (type.getName().equals(typeName))
				{
					return type;
				}
			}
			return null;
		}
	}
	
	
	//++++++++++++//
	// ATTRIBUTES //
	//++++++++++++//
	
	private File mFile;
	public File getFile(){ return mFile; }

	private Map<RELATION_TYPE, LinkedPhoto> mRelations;
	public Map<RELATION_TYPE, LinkedPhoto> getRelations(){ return mRelations; }
	

	//++++++++++++++//
	// CONSTRUCTORS //
	//++++++++++++++//
	
	public LinkedPhoto(File file)
	{
		this.mFile = file;
		this.mRelations = new HashMap<LinkedPhoto.RELATION_TYPE, LinkedPhoto>();
	}
	

	//+++++++++//
	// METHODS //
	//+++++++++//
	
	/**
	 * 
	 * @param relationType type of the relation
	 * @return the photo specified by the relation, null if not exists
	 */
	public LinkedPhoto getlinkedPhotoFromRelationType(
			RELATION_TYPE relationType
			)
	{
		return this.mRelations.get(relationType);
	}
	
	/**
	 * 
	 * @param relationType the relation type
	 * @param linkedPhoto the linked photo
	 */
	public void addLinkedFonction(RELATION_TYPE relationType, LinkedPhoto linkedPhoto)
	{
		this.mRelations.put(relationType, linkedPhoto);
	}
	
	@Override
	public String toString()
	{
		String output = this.mFile.getName();
		String ls = System.getProperty("line.separator");
		output += ls + "{" + ls;

		for (Entry<RELATION_TYPE, LinkedPhoto> entry : this.mRelations.entrySet())
		{
			output += "  " + entry.getKey().getName() + " = "
					+ entry.getValue().getFile().getName() + ls;
		}
		output += "}";
		
		return output;
	}
	

	//++++++++++++++++//
	// STATIC METHODS //
	//++++++++++++++++//
	
	/**
	 * 
	 * @param graphe contains all LinkedPhotos not linked
	 * @return the graph with all LinkedPhotos linked
	 * @throws JDOMException
	 * @throws IOException
	 */
	public static Graphe<LinkedPhoto> computeLinks(File dir)
			throws JDOMException, IOException
	{
		Graphe<LinkedPhoto> graphe = new Graphe<LinkedPhoto>(dir.getName());
		
		SAXBuilder sxb = new SAXBuilder();
		File relationsXML = new File(dir, "relations.xml");
		if ( ! relationsXML.isFile())
		{
			throw new IOException("File relations.xml does not exist");
		}
		Document document = sxb.build(relationsXML);
		Element racine = document.getRootElement();
		
		Map<String, LinkedPhoto> map = new HashMap<String, LinkedPhoto>();
		
		List<Element> photos = racine.getChildren("photo");
		for (Element photoElt : photos)
		{
			String name = photoElt.getAttributeValue("name");
			if (name == null)
			{
				throw new IOException("Element photo does not contain attribute name");
			}
			LinkedPhoto linkedPhoto = map.get(name);
			if (linkedPhoto == null)
			{
				File photo = new File(dir, name);
				if ( ! photo.isFile())
				{
					throw new FileNotFoundException(photo.getAbsolutePath() + "is not found");
				}
				map.put(name, new LinkedPhoto(photo));
				linkedPhoto = map.get(name);
			}
			List<Element> relations = photoElt.getChildren("relation");
			for (Element relation : relations)
			{
				name = relation.getAttributeValue("name");
				if (name == null)
				{
					throw new IOException("Element photo does not contain attribute name");
				}
				LinkedPhoto relativeLinkedPhoto = map.get(name);
				if (relativeLinkedPhoto == null)
				{
					File photo = new File(dir, name);
					if ( ! photo.isFile())
					{
						throw new FileNotFoundException(photo.getAbsolutePath() + "is not found");
					}
					map.put(name, new LinkedPhoto(photo));
					relativeLinkedPhoto = map.get(name);
				}
				String typeName = relation.getAttributeValue("type");
				if (typeName == null)
				{
					throw new IOException("Element relation does not contain attribute type");
				}
				RELATION_TYPE relationType = RELATION_TYPE.getTypeFromName(typeName);
				if (relationType == null)
				{
					throw new IOException("Attribute type of element relation unrecognized");
				}
				linkedPhoto.addLinkedFonction(relationType, relativeLinkedPhoto);
			}
			graphe.addItem(linkedPhoto);
		}
		
		return graphe;
	}
}
